package br.fagoc.easyds.datastructure;

import java.util.ArrayList;
import java.util.List;

import br.fagoc.easyds.cell.DequeCell;
import br.fagoc.easyds.cell.SinglyLinkedListCell;
import br.fagoc.easyds.exception.EmptyStructureException;
import br.fagoc.easyds.ui.jgraph.GraphCellManipulator;
import br.fagoc.easyds.ui.jgraph.GraphEdgeManipulator;
import br.fagoc.easyds.ui.jgraph.GraphManipulator;

import com.mxgraph.model.mxCell;
import com.mxgraph.model.mxICell;
import com.mxgraph.view.mxGraph;

public class Deque {
	private final double CELULA_LARGURA = 80;
	private final double CELULA_ALTURA = 50;
	private final double CELULA_EIXO_X_ORIGEM = 0;
	private final double CELULA_EIXO_Y_ORIGEM = 100;
	private final double CELULA_EIXO_X_DESTINO = 20;
	private final double CELULA_EIXO_Y_DESTINO = 20;
	private final double EIXO_X_LIMITE_REMOCAO = 0 - CELULA_LARGURA;
	private final double EIXO_Y_LIMITE_REMOCAO = 100;
	private final double MODIFICADOR_EIXO_X = 100;
	
	private List<DequeCell> list = new ArrayList<DequeCell>();
	
	private GraphCellManipulator graphCellManipulator;
	private GraphEdgeManipulator graphEdgeManipulator;
	private GraphManipulator graphManipulator;
	
	
	public Deque(mxGraph graph){
		this.graphManipulator = new GraphManipulator(graph);
		this.graphCellManipulator = new GraphCellManipulator(graph);
		this.graphEdgeManipulator = new GraphEdgeManipulator(graph);
	}
	
	public void pushOnFront(String value){
		double xAxisCell = getXAxisOnFront();
		double yAxisCell = getYAxisOnFront();
		
		mxCell graphCell = graphCellManipulator.createRectangularCell(value, xAxisCell, yAxisCell);
		DequeCell cell = new DequeCell(graphCell);
		
		if(list.size() > 0){
			DequeCell childCell = list.get(0);
			mxICell edgeFromCellToChild = graphEdgeManipulator.createEdge(cell.getGraphCell(), childCell.getGraphCell());
			
			cell.setChildCell(childCell, edgeFromCellToChild);
			childCell.setParentCell(cell);
		}
		
		list.add(0, cell);
		atualizarPosicoes();
		
		graphCellManipulator.horizontalTranslation(cell.getGraphCell(), CELULA_EIXO_X_ORIGEM, CELULA_EIXO_Y_ORIGEM, xAxisCell);
		graphCellManipulator.verticalTranslation(cell.getGraphCell(), xAxisCell, CELULA_EIXO_Y_ORIGEM, yAxisCell);
		
		if(cell.hasChild()){
			graphEdgeManipulator.drawEdge(cell.getChildEdge(), cell.getGraphCell(), cell.getChildCell().getGraphCell());
		}
		
		graphCellManipulator.blinkCell(cell.getGraphCell());
	}
	
	public void pushOnBack(String value){
		double xAxisCell = getXAxisOnBack();
		double yAxisCell = getYAxisOnBack();
		
		mxCell graphCell = graphCellManipulator.createRectangularCell(value, xAxisCell, yAxisCell);
		DequeCell cell = new DequeCell(graphCell);
		
		if(list.size() > 0){
			DequeCell parentCell = list.get(list.size()-1);
			mxICell edgeFromParentToCell = graphEdgeManipulator.createEdge(parentCell.getGraphCell(), cell.getGraphCell());
			
			cell.setParentCell(parentCell);
			parentCell.setChildCell(cell, edgeFromParentToCell);
		}
		
		list.add(list.size(), cell);
		
		graphCellManipulator.horizontalTranslation(cell.getGraphCell(), CELULA_EIXO_X_ORIGEM, CELULA_EIXO_Y_ORIGEM, xAxisCell);
		graphCellManipulator.verticalTranslation(cell.getGraphCell(), xAxisCell, CELULA_EIXO_Y_ORIGEM, yAxisCell);
		
		if(cell.hasParent()){
			graphEdgeManipulator.drawEdge(cell.getParentCell().getChildEdge(), cell.getParentCell().getGraphCell(), cell.getGraphCell());
		}
		
		graphCellManipulator.blinkCell(cell.getGraphCell());
	}
	
	public DequeCell popOnFront() throws EmptyStructureException{
		if(list.size() == 0){
			throw new EmptyStructureException();
		}
		else{
			DequeCell cell = list.remove(0);
			
			graphCellManipulator.blinkCell(cell.getGraphCell());
			
			if(cell.hasChild()){
				graphEdgeManipulator.removeEdge(cell.getGraphCell(), cell.getChildEdge());

				cell.getChildCell().removeParent();
				cell.removeChild();
			}
			
			graphCellManipulator.verticalTranslation(cell.getGraphCell(), 
				cell.getGraphCell().getGeometry().getX(), cell.getGraphCell().getGeometry().getY(), CELULA_EIXO_Y_ORIGEM);
			
			atualizarPosicoes();
			
			graphCellManipulator.horizontalTranslation(cell.getGraphCell(), 
				cell.getGraphCell().getGeometry().getX(), cell.getGraphCell().getGeometry().getY(), -CELULA_LARGURA);
			graphCellManipulator.removeCell(cell.getGraphCell());
			
			return null;
		}
	}
	
	public DequeCell popOnBack() throws EmptyStructureException{
		if(list.size() == 0){
			throw new EmptyStructureException();
		}
		else{
			DequeCell cell = list.remove(list.size() - 1);
			
			graphCellManipulator.blinkCell(cell.getGraphCell());
			
			if(cell.hasParent()){
				graphEdgeManipulator.removeEdge(cell.getParentCell().getGraphCell(), cell.getParentCell().getChildEdge());

				cell.getParentCell().removeParent();
				cell.removeParent();
			}
			
			graphCellManipulator.verticalTranslation(cell.getGraphCell(), 
				cell.getGraphCell().getGeometry().getX(), cell.getGraphCell().getGeometry().getY(), CELULA_EIXO_Y_ORIGEM);
			graphCellManipulator.horizontalTranslation(cell.getGraphCell(), 
				cell.getGraphCell().getGeometry().getX(), cell.getGraphCell().getGeometry().getY(), -CELULA_LARGURA);
			
			graphCellManipulator.removeCell(cell.getGraphCell());
			
			return null;
		}
	}
	
	public void peekFront() throws EmptyStructureException{
		if(list.size() == 0){
			throw new EmptyStructureException();
		}
		else{
			DequeCell cell = list.get(0);
			DequeCell returnedCell = new DequeCell(graphCellManipulator.createRectangularCell((String) cell.getGraphCell().getValue(), 
					cell.getGraphCell().getGeometry().getX(), cell.getGraphCell().getGeometry().getY()));
			
			graphCellManipulator.blinkCell(cell.getGraphCell());
			
			graphCellManipulator.verticalTranslation(returnedCell.getGraphCell(), 
				returnedCell.getGraphCell().getGeometry().getX(), returnedCell.getGraphCell().getGeometry().getY(), CELULA_EIXO_Y_ORIGEM);
			graphCellManipulator.horizontalTranslation(returnedCell.getGraphCell(), 
				returnedCell.getGraphCell().getGeometry().getX(), returnedCell.getGraphCell().getGeometry().getY(), -CELULA_LARGURA);
			
			graphCellManipulator.removeCell(returnedCell.getGraphCell());
		}
	}
	
	public void peekBack() throws EmptyStructureException{
		if(list.size() == 0){
			throw new EmptyStructureException();
		}
		else{
			DequeCell cell = list.get(list.size()-1);
			DequeCell returnedCell = new DequeCell(graphCellManipulator.createRectangularCell((String) cell.getGraphCell().getValue(), 
					cell.getGraphCell().getGeometry().getX(), cell.getGraphCell().getGeometry().getY()));
			
			graphCellManipulator.blinkCell(cell.getGraphCell());
			
			graphCellManipulator.verticalTranslation(returnedCell.getGraphCell(), 
				returnedCell.getGraphCell().getGeometry().getX(), returnedCell.getGraphCell().getGeometry().getY(), CELULA_EIXO_Y_ORIGEM);
			graphCellManipulator.horizontalTranslation(returnedCell.getGraphCell(), 
				returnedCell.getGraphCell().getGeometry().getX(), returnedCell.getGraphCell().getGeometry().getY(), -CELULA_LARGURA);
			
			graphCellManipulator.removeCell(returnedCell.getGraphCell());
		}
	}
	
	private void atualizarPosicoes() {
		for(int i = 0; i < list.size(); i++){
			list.get(i).getGraphCell().getGeometry().setX(20 + (MODIFICADOR_EIXO_X * i));
		}
	}
	
	public double getXAxisOnBack(){
		return CELULA_EIXO_X_DESTINO + (list.size() * MODIFICADOR_EIXO_X);
	}
	
	public double getXAxisOnFront(){
		return CELULA_EIXO_X_DESTINO;
	}
	
	public double getYAxisOnBack(){
		return CELULA_EIXO_Y_DESTINO;
	}
	
	public double getYAxisOnFront(){
		return CELULA_EIXO_Y_DESTINO;
	}
}
